#include "http_my.h"

#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

static esp_err_t handleGetUrlPath(httpd_req_t *pRequest);
static esp_err_t handlePostUrlPath(httpd_req_t *pRequest);
static esp_err_t findRequestData(char *pRequestData);

static httpd_req_t *s_pRequest = NULL;

static httpd_uri_t s_uriClientGet =
    {
        .uri = "/client",
        .method = HTTP_GET,
        .handler = handleGetUrlPath,
        .user_ctx = NULL};

static httpd_uri_t s_uriConfigPost =
    {
        .uri = "/config",
        .method = HTTP_POST,
        .handler = handlePostUrlPath,
        .user_ctx = NULL};

static const char *TAG = "user_http_server";

/* HTTP服务器初始化 */
httpd_handle_t HttpServerInit(void)
{
    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();

    /* 启动HTTP服务器 */
    ESP_LOGI(TAG, "Starting HTTP server on port: '%d'", config.server_port);
    oled_http_start_port();
    // uart_write_bytes(UART_NUM_0, "http start", strlen("http start"));
    if (httpd_start(&server, &config) == ESP_OK)
    {
        /* 注册URI处理程序 */
        httpd_register_uri_handler(server, &s_uriConfigPost);
        httpd_register_uri_handler(server, &s_uriClientGet);
        return server;
    }

    ESP_LOGI(TAG, "Error starting server!");
    return NULL;
}

/**
 @brief HTTP GET请求URL处理
 @param pRequest -[in] HTTP请求结构体
 @return 错误码
*/
static esp_err_t handleGetUrlPath(httpd_req_t *pRequest)
{
    esp_err_t result = ESP_FAIL;
    char *pBuffer;
    size_t bufferLength;

    cJSON *pResult = cJSON_CreateObject();
    bufferLength = httpd_req_get_url_query_len(pRequest) + 1;
    if (bufferLength > 1)
    {
        pBuffer = malloc(bufferLength);
        if (httpd_req_get_url_query_str(pRequest, pBuffer, bufferLength) == ESP_OK)
        {
            ESP_LOGI(TAG, "Found URL query => %s", pBuffer);
            s_pRequest = pRequest;
            char requestData[RESPONSE_DATA_SIZE] = {0};
            result = findRequestData(requestData);

            if (strcmp(pBuffer, "command=info") == 0)
            {
                queryClientInfo(pResult);
            }
        }
        free(pBuffer);
    }
    return result;
}

/**
 @brief HTTP POST请求URL处理
 @param pRequest -[in] HTTP请求结构体
 @return 错误码
*/
static esp_err_t handlePostUrlPath(httpd_req_t *pRequest)
{
    esp_err_t result = ESP_FAIL;
    char *pBuffer;
    size_t bufferLength;

    cJSON *pResult = cJSON_CreateObject();
    /* Read URL query string length and allocate memory for length + 1,
     * extra byte for null termination */
    bufferLength = httpd_req_get_url_query_len(pRequest) + 1;
    if (bufferLength > 1)
    {
        pBuffer = malloc(bufferLength);
        if (httpd_req_get_url_query_str(pRequest, pBuffer, bufferLength) == ESP_OK)
        {
            ESP_LOGI(TAG, "Found URL query => %s", pBuffer);
            s_pRequest = pRequest;
            char requestData[REQUEST_DATA_SIZE] = {0};
            result = findRequestData(requestData);

            if (strcmp(pBuffer, "command=wifi") == 0)
            {
                configWifi(requestData, pResult);
            }

            if (strcmp(pBuffer, "command=userinfo") == 0)
            {
                configUserInfo(requestData, pResult);
            }

            if (strcmp(pBuffer, "command=deviceinfo") == 0)
            {
                configDeviceInfo(requestData, pResult);
            }

            if (strcmp(pBuffer, "command=paraminfo") == 0)
            {
                configDHTInfo(requestData, pResult);
            }

            if (strcmp(pBuffer, "command=noparaminfo") == 0)
            {
                configDHTInfo(requestData, pResult);
            }

            free(pBuffer);
        }
    }
    return result;
}

/**
 @brief 查找请求数据
 @param pRequestData -[out] 请求的数据
 @return 错误码
*/
static esp_err_t findRequestData(char *pRequestData)
{
    int result, remains = s_pRequest->content_len;
    printf("content length: %d\n", remains);

    while (remains > 0)
    {
        /* 从HTTP请求读取内容数据 */
        if ((result = httpd_req_recv(s_pRequest, pRequestData, MIN(remains, REQUEST_DATA_SIZE))) <= 0)
        {
            if (result == HTTPD_SOCK_ERR_TIMEOUT)
            {
                /* 发生超时继续接收 */
                continue;
            }
            return ESP_FAIL;
        }
        remains -= result;

        /* log data received */
        ESP_LOGI(TAG, "========== RECEIVED DATA ==========");
        ESP_LOGI(TAG, "%.*s", result, pRequestData);
        ESP_LOGI(TAG, "===================================");
    }
    return ESP_OK;
}

/**
 @brief JSON格式封装响应数据
 @param responseOk -[in] 响应是否成功
 @param pSendData -[in&out] 要封装的发送数据
 @return 无
*/
void jsonPackageResponseData(bool responseOK, char *pSendData, cJSON *pResult)
{
    // cJSON *pRoot = cJSON_CreateObject();
    char statusCode[16] = {0};

    if (responseOK)
    {
        sprintf(statusCode, "200");
    }
    else
    {
        sprintf(statusCode, "400");
    }

    cJSON_AddStringToObject(pResult, "status", statusCode);

    char *tempBuffer = cJSON_Print(pResult);
    strcat(pSendData, tempBuffer);

    free((void *)tempBuffer);
    cJSON_Delete(pResult);
}

/**
 @brief 发送POST请求的HTTP响应
 @param responseOk -[in] 响应是否成功
 @param pResponseData -[in] 响应数据
 @return 无
*/
void sendPostResponse(bool responseOk, char *pResponseData, cJSON *pResult)
{
    jsonPackageResponseData(responseOk, pResponseData, pResult);

    if (responseOk)
    {
        httpd_resp_set_status(s_pRequest, HTTPD_200);
    }
    else
    {
        httpd_resp_set_status(s_pRequest, HTTPD_400);
    }

    httpd_resp_send(s_pRequest, pResponseData, strlen(pResponseData));
}

/**
 @brief 发送GET请求HTTP响应
 @param responseOk -[in] 响应是否成功
 @param pResponseData -[in] 响应数据
 @return 无
*/
void sendGetResponse(bool responseOk, char *pResponseData, cJSON *pResult)
{
    jsonPackageResponseData(responseOk, pResponseData, pResult);
    if (responseOk)
    {
        httpd_resp_set_status(s_pRequest, HTTPD_200); // 设置响应状态200 OK
    }
    else
    {
        httpd_resp_set_status(s_pRequest, HTTPD_400); // 设置响应状态400 Bad Request
    }

    httpd_resp_send(s_pRequest, pResponseData, strlen(pResponseData)); // 发送响应
}